package com.gitee.dolt.boot;

import cn.hutool.core.util.StrUtil;
import com.gitee.dolt.boot.decrypt.BCryptPasswordEncoder;
import com.gitee.dolt.boot.decrypt.DecryptAspect;
import com.gitee.dolt.boot.decrypt.PasswordEncoder;
import com.gitee.dolt.boot.properties.BootProperties;
import com.gitee.dolt.boot.lock.LockAspect;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/**
 * swagger 包扫描配置
 *
 * @author LYH
 */
@Configuration
@EnableConfigurationProperties(BootProperties.class)
@Slf4j
@RequiredArgsConstructor
public class BootAutoConfiguration {

    private final BootProperties bootProperties;

    private static final char CORS_SPLIT = ';';

    @Bean
    @ConditionalOnProperty(prefix = BootProperties.PREFIX + ".lock", name = "enabled", havingValue = "true", matchIfMissing = true)
    public LockAspect lockAspect() {
        return new LockAspect();
    }

    @Bean
    @ConditionalOnProperty(prefix = BootProperties.PREFIX + ".decrypt", name = "enabled", havingValue = "true", matchIfMissing = true)
    public DecryptAspect decryptAspect(BootProperties bootProperties) {
        return new DecryptAspect(bootProperties);
    }

    /**
     * 实际中如果这样配置也是可行的【驼峰】
     * boot: printBean: true
     *
     * @param applicationContext
     * @return
     */
    @Bean
    @ConditionalOnExpression("${dolt.boot.print-bean:false}")
    public CommandLineRunner printBeanInfoRunner(ApplicationContext applicationContext) {
        return args -> {
            String[] names = applicationContext.getBeanDefinitionNames();
            int index = 1;
            log.info("--------------start print bean--------------");
            for (String name : names) {
                log.info("{}：{} --> {}", index++, name, applicationContext.getBean(name).getClass());
            }
            log.info("--------------end print bean--------------");
        };
    }

    @Bean
    @ConditionalOnMissingBean
    public CorsFilter corsFilter() {
        BootProperties.CorsProperties corsProperties = bootProperties.getCors();
        UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource();
        CorsConfiguration cors = new CorsConfiguration();

        // 是否发送Cookie信息
        cors.setAllowCredentials(corsProperties.isAllowCredentials());
        // 放行哪些原始域
        StrUtil.split(corsProperties.getAllowedOrigin(), CORS_SPLIT).forEach(e -> cors.addAllowedOrigin(e));
        // 放行哪些原始域(头部信息)
        StrUtil.split(corsProperties.getAllowedHeader(), CORS_SPLIT).forEach(e -> cors.addAllowedHeader(e));
        // 放行哪些原始域(请求方式)
        StrUtil.split(corsProperties.getAllowedMethod(), CORS_SPLIT).forEach(e -> cors.addAllowedMethod(e));

        configurationSource.registerCorsConfiguration(corsProperties.getPath(), cors);
        return new CorsFilter(configurationSource);
    }

    @Bean
    @ConditionalOnMissingBean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
